import glob
import shutil
import subprocess
import sys
import os
import re
import threading
import time
import uuid
from enum import Enum

from PySide6.QtGui import QPixmap, QStandardItem, QStandardItemModel, QIcon, QImageWriter, \
    QPainter, QPen, QColor, QImage
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QTableView, \
    QDialog, QCheckBox, QHBoxLayout, QPushButton, QToolButton, QFileDialog, QMessageBox, QHeaderView, QLabel, QSlider
from PySide6.QtCore import Qt, QFileInfo, Slot, QSize, QModelIndex
from PIL import Image as PILImage

# 当前处理模式的枚举类
class C_MODE(Enum):
    MODE_0 = "0"  # 初始
    MODE_1 = "1"  # 图片 可编辑
    MODE_2 = "2"  # .iconset 可编辑
    MODE_3 = "3"  # .icns .app 只查看 没有其它操作


class DiscreteSlider(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent
        self.fixed_values = [0, 1, 2, 3]
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout(self)
        layout.addStretch(1)
        self.info_label = QLabel("最内侧虚线:大图基准线 ")
        self.info_label2 = QLabel("中间虚线:小图基准线 ")
        layout.addWidget(self.info_label)
        layout.addWidget(self.info_label2)

        self.value_label = QLabel("透明占比: ")
        layout.addWidget(self.value_label)

        self.slider = QSlider(Qt.Horizontal, self)
        self.slider.setMinimum(0)
        self.slider.setMaximum(3)  # 4个固定值：0, 1, 2, 3
        self.slider.setSingleStep(1)  # 确保步长为1，即使实际上我们不连续使用这些值
        self.slider.setPageStep(1)  # 同上
        self.slider.setTickPosition(QSlider.TicksAbove)
        self.slider.setTickInterval(1)  # 每个刻度间隔1，但实际显示的值会调整到我们的固定值
        self.slider.valueChanged.connect(self.update_value_label)
        self.slider.sliderReleased.connect(self.snap_to_nearest)
        self.update_value_label()
        layout.addWidget(self.slider)

        self.setLayout(layout)

    def update_value_label(self):
        """更新显示当前滑块的值，尽管这个值可能在释放滑块后被修正到最近的固定值"""
        value = self.slider.value()
        self.value_label.setText(f"透明占比: {value}")

    def set_value(self, value):
        current_value = self.slider.value()
        if current_value == value:
            return
        nearest = min(self.fixed_values, key=lambda x: abs(x - value))
        self.slider.setValue(nearest)
        self.update_value_label()  # 更新标签以反映修正后的值

    def snap_to_nearest(self):
        """释放滑块时，将滑块的值修正到最近的固定值"""
        current_value = self.slider.value()
        nearest = min(self.fixed_values, key=lambda x: abs(x - current_value))
        self.slider.setValue(nearest)
        self.update_value_label()  # 更新标签以反映修正后的值
        self.parent.reset_png(nearest)


class ImageWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent
        self.pixmap = QPixmap()
        self.setAcceptDrops(True)  # 允许接受拖拽事件
        self.borderWidth = 1  # 边框宽度

    def setPixmap(self, pixmap):
        self.pixmap = pixmap
        self.update()  # 更新显示

    def paintEvent(self, event):
        painter = QPainter(self)
        # 绘制虚线边框
        pen = QPen(QColor(0, 0, 0), self.borderWidth)  # 设置边框颜色和宽度
        pen.setStyle(Qt.DashLine)  # 设置边框样式为虚心线
        painter.setPen(pen)
        painter.setBrush(Qt.NoBrush)  # 不填充边框内部
        painter.drawRect(self.rect().adjusted(1, 1, -self.borderWidth, -self.borderWidth))
        # 绘制图片
        point = self.rect()  # .topleft 从窗口的左上角开始绘制
        painter.drawPixmap(point, self.pixmap)

        # 绘制虚线边框
        pen_16 = QPen(QColor(0, 0, 0), self.borderWidth)  # 设置边框颜色和宽度
        pen_16.setStyle(Qt.DashLine)  # 设置边框样式为虚心线
        painter.setPen(pen_16)
        painter.setBrush(Qt.NoBrush)  # 不填充边框内部
        painter.drawRect(self.rect().adjusted(16, 16, -16, -16))

        pen_128 = QPen(QColor(0, 0, 0), self.borderWidth)  # 设置边框颜色和宽度
        pen_128.setStyle(Qt.DashLine)  # 设置边框样式为虚心线
        painter.setPen(pen_128)
        painter.setBrush(Qt.NoBrush)  # 不填充边框内部
        painter.drawRect(self.rect().adjusted(24, 24, -24, -24))

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            url = event.mimeData().urls()[0]
            local_file = url.toLocalFile()
            if local_file:
                print(f"Dropped file: {local_file}")
                self.parent.check_file(local_file)

    def loadPixmapFromFile(self, file_path):
        pixmap = QPixmap(file_path)
        self.loadPixmapFromPixmap(pixmap)

    def loadPixmapFromPixmap(self, pixmap):
        if not pixmap.isNull():
            self.setPixmap(pixmap)


class HoverButton(QToolButton):
    def __init__(self, icon_path, parent=None):
        super().__init__(parent)
        self.setIcon(QIcon(icon_path))  # 设置图标
        self.setIconSize(QSize(32, 32))  # 设置图标大小
        self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)  # 文本显示在图标下（如果需要的话）
        self.setAutoRaise(True)  # 设置按钮在无操作时自动平坦，以便更好地与背景融合
        self.setFixedSize(32, 35)  # 设置按钮固定大小
        # 设置样式表以去掉边框并添加背景色变化效果
        self.setStyleSheet("""
            QToolButton {
                border: none; /* 去掉边框 */
                background-color: transparent; /* 透明背景 */
            }
            
            QToolButton:hover {
                background-color: #ddd; /* 鼠标悬停时的背景色 */
            }
            
            QToolButton:pressed {
                background-color: #bbb; /* 按钮被按下时的背景色 */
            }
        """)


class MultiCheckDialog(QDialog):
    def __init__(self, parent=None, image_width=1024):
        super().__init__(parent)
        self.image_width = image_width
        self.initUI()

    def initUI(self):
        self.setWindowTitle('选择ico图片的尺寸')
        self.setFixedWidth(256)
        # 创建垂直布局
        layout = QVBoxLayout()
        info_label = QLabel("根据图片大小展示尺寸选项\n建议图片长宽大于256或512")
        layout.addWidget(info_label)
        img_sizes = [16, 32, 64, 128, 256, 512]
        # 创建多选框
        self.checkboxes = {}
        for img_size in img_sizes:
            if img_size > self.image_width + 5:
                break
            else:
                name = f'{img_size}x{img_size}'
                checkbox = QCheckBox(name)
                if img_size == 16 or img_size == 128:
                    checkbox.setChecked(True)
                self.checkboxes.setdefault(name, checkbox)
            if img_size * 2 > self.image_width + 5:
                break
            else:
                name_2 = f'{img_size}x{img_size}@2x'
                checkbox = QCheckBox(name_2)
                if img_size == 16 or img_size == 128:
                    checkbox.setChecked(True)
                self.checkboxes.setdefault(name_2, checkbox)
        for label, checkbox in self.checkboxes.items():
            layout.addWidget(checkbox)

        # 创建水平布局来放置按钮
        button_layout = QHBoxLayout()
        self.okButton = QPushButton('完成')
        self.okButton.clicked.connect(self.accept)
        button_layout.addWidget(self.okButton)
        # 创建一个取消按钮（可选）
        self.cancelButton = QPushButton('取消')
        self.cancelButton.clicked.connect(self.reject)
        button_layout.addWidget(self.cancelButton)


        # 将按钮添加到布局底部
        layout.addLayout(button_layout)

        # 设置对话框的布局
        self.setLayout(layout)

    @Slot()
    def accept(self):
        # 用户点击了完成按钮，获取多选框的状态
        selected_options = {label: checkbox.isChecked() for label, checkbox in self.checkboxes.items()}
        print("选中的选项：", selected_options)
        # 在这里可以执行后续的逻辑
        self.parent().selected_options = selected_options
        super().accept()


class MainWin(QWidget):
    def __init__(self):
        super().__init__()
        self.cache_path = self.mk_cache_dir(".jiesuoge/ico")
        self.base_path = self.get_base_path()
        self.output_path = f"{self.cache_path}/output.icns"
        self.temp_clip_path = f"{self.cache_path}/temp_clipboard.png"  # 缓存剪切板图片或上传拖拽的原始图片地址
        self.temp_iconset = f"{self.cache_path}/temp_icons.iconset"  # 缓存生成的多尺寸png图片 用于导出.icns
        # 清理一下临时文件夹下的文件
        self.clear_temp_dir()
        self.painter = None
        self.image_extensions = {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff', '.ico', '.webp', '.heif', '.heic'}
        self.selected_options = {}  # 缓存要生成png的各种尺寸
        self.current_table_row = -1  # 缓存点击table行
        self.current_mode = C_MODE.MODE_0  # 当前模式
        self.img_sizes = [16,32,64,128,256,512]
        self.ratios = {'16x16': 1.147,
                       '16x16@2x': 1.147,
                       '32x32': 1.147,
                       '32x32@2x': 1.147,
                       '64x64': 1.235,
                       '64x64@2x': 1.235,
                       '128x128': 1.235,
                       '128x128@2x': 1.235,
                       '256x256': 1.235,
                       '256x256@2x': 1.235,
                       '512x512': 1.235,
                       '512x512@2x': 1.235,
                       }
        self.slides_vals = {
            1.0: 0,
            1.075: 1,
            1.147: 2,
            1.235: 4,
        }
        layout = QVBoxLayout()

        # 创建一个水平布局
        label_layout = QHBoxLayout()

        self.view = ImageWidget(self)
        self.view.setFixedWidth(256)
        self.view.setFixedHeight(256)
        self.view.loadPixmapFromFile(f"{self.base_path}/resource/info.png")
        label_layout.addWidget(self.view)
        label_layout.addStretch(1)

        # 微调
        self.trans_slider = DiscreteSlider(self)
        self.trans_slider.setEnabled(False)  # 初始不可用
        label_layout.addWidget(self.trans_slider)
        label_layout.addStretch(1)

        layout.addLayout(label_layout)

        # 创建表格模型
        self.model = QStandardItemModel(0, 4)
        self.model.setHorizontalHeaderLabels(['名称（可点击）', '大小', '地址（可点击查看）', '尺寸'])

        # 表格视图
        self.tableView = QTableView()
        self.tableView.setMinimumWidth(450)
        self.tableView.setModel(self.model)
        self.tableView.horizontalHeader().setStretchLastSection(True)

        # 连接 clicked 信号到槽函数
        self.tableView.clicked.connect(self.on_table_clicked)
        layout.addWidget(self.tableView)

        button_layout = QHBoxLayout()

        upload_button = HoverButton(f"{self.base_path}/resource/upload.png")
        upload_button.setToolTip('选择图片｜.icns | .app')  # 设置工具提示
        upload_button.clicked.connect(self.on_upload_clicked)  # 连接点击信号到槽
        button_layout.addWidget(upload_button)

        self.remove_button = HoverButton(f"{self.base_path}/resource/remove.png")
        self.remove_button.setToolTip('删除不需要打包的图片')  # 设置工具提示
        self.remove_button.clicked.connect(self.on_remove_clicked)  # 连接点击信号到槽
        self.remove_button.setEnabled(False)
        button_layout.addWidget(self.remove_button)

        # 添加一个伸缩因子来确保按钮组靠右
        button_layout.addStretch(1)
        info_label = QLabel("生成.icns前建议对图片进行无损压缩")
        button_layout.addWidget(info_label)
        self.save_button = HoverButton(f"{self.base_path}/resource/save.png")
        self.save_button.setToolTip('生成.icns文件')  # 设置工具提示
        self.save_button.clicked.connect(self.save_icns)  # 连接点击信号到槽
        self.save_button.setEnabled(False)
        button_layout.addWidget(self.save_button)

        layout.addLayout(button_layout)

        self.setLayout(layout)

    def get_option_from_name(self, file_name):
        # 校验是否标准命名
        if file_name.endswith('.png') and file_name.startswith('icon_'):
            option = file_name[5:-4]
            if option in self.ratios:
                return option

        # 根据文件尺寸判断option
        img_size = self.model.item(self.current_table_row, 3).text()
        size = str.split(img_size,'x')
        width = int(size[0])
        height = int(size[1])
        nearest = min(self.img_sizes, key=lambda x: abs(x - max(width,height)))
        option = f'{nearest}x{nearest}'
        print(f'option:{option}')
        return option

    def reset_png(self, val):
        if self.current_table_row >= 0:
            file_name_item = self.model.item(self.current_table_row, 0)
            file_name = file_name_item.text()
            option = self.get_option_from_name(file_name)
            if not option:
                return
        else:
            return

        try:
            # 遍历字典的键值对
            ico_size = self.get_ico_size(option)
            ratio = self.get_ratio_by_val(val)
            if not ratio:
                ratio = 1.235
            # 获取原文件地址
            if self.current_mode == C_MODE.MODE_2:
                src_path = self.model.item(self.current_table_row, 2).data()
            elif self.current_mode == C_MODE.MODE_3:
                item_2 = self.model.item(self.current_table_row, 2)
                file_path = item_2.text()
                src_path = item_2.data()
                # 先从缓存取
                if not src_path:
                    os.makedirs(f'{self.cache_path}/temp', exist_ok=True)
                    src_path = os.path.join(self.cache_path, f'temp/{uuid.uuid4()}.png')
                    shutil.copy2(file_path, src_path)
                    item_2.setData(src_path)
            else:
                src_path = self.temp_clip_path
            file_name = file_name_item.text()

            png_path = self.crop_and_square_png(src_path, ratio)
            output_path = f'{self.temp_iconset}/{file_name}'
            subprocess.run(["sips", "-z", str(ico_size), str(ico_size), png_path, "--out",
                            output_path], check=True)
            # 缓存调整数据到单元格0
            file_name_item.setData(str(val))

            self.view.loadPixmapFromFile(output_path)  # 重新加载图片
            os.remove(png_path)
        except Exception as e:
            self.show_message_box(f"生成ico文件失败！{e}")

    def get_ratio_by_val(self, v):
        for key, val in self.slides_vals.items():
            if val == v:
                return key

    def get_base_path(self):
        # 检查是否在PyInstaller的onefile模式下运行
        if getattr(sys, 'frozen', False):
            # 如果是，则_MEIPASS属性会包含临时解压的目录路径
            return sys._MEIPASS
        else:
            return os.path.join(os.path.dirname(sys.argv[0]))

    def clear_temp_dir(self):
        temp = f'{self.cache_path}/temp'
        if os.path.exists(temp):
            for file in os.listdir(temp):
                os.remove(os.path.join(temp,file))

        if os.path.exists(self.temp_iconset):
            if os.path.isdir(self.temp_iconset):
                shutil.rmtree(self.temp_iconset)
                os.mkdir(self.temp_iconset)
        else:
            os.mkdir(self.temp_iconset)

    def on_upload_clicked(self):
        try:
            options = QFileDialog.Options()
            file_path, _ = QFileDialog.getOpenFileName(self, "选择图标文件", "",
                                                       "All Files (*.*);;PNG Files (*.png);;JPEG Files (*.jpg);;Iconset Files (*.iconset);;Icon Files (*.icns)",
                                                       options=options)
        except Exception as e:
            self.show_message_box("选择文件失败，请重新选择")
            return
        if file_path:
            print(f"选中的文件: {file_path}")
            self.check_file(file_path)

    def is_image_file(self, file_name):
        _, file_extension = os.path.splitext(file_name)
        return file_extension in self.image_extensions

    # 获取清晰度最高的图片
    def find_highest_image(self, directory):
        max_resolution = (0, 0)  # 初始化最大分辨率为0x0
        max_resolution_image_path = None

        # 遍历指定目录下的所有文件
        for file in os.listdir(directory):
            # 提取文件的扩展名
            if self.is_image_file(file):
                file_path = os.path.join(directory, file)
                try:
                    # 使用PIL打开图片并获取其尺寸
                    with PILImage.open(file_path) as img:
                        width, height = img.size
                        resolution = (width, height)

                        # 比较当前图片的分辨率是否更高
                        if resolution > max_resolution:
                            max_resolution = resolution
                            max_resolution_image_path = file_path
                except Exception as e:
                    print(f"Error opening file {file_path}: {e}")

        return max_resolution_image_path

    # 复制文件到指定文件夹
    def cp_imgs_to_dir(self, src_dir, dst_dir):
        # 确保目标目录存在，如果不存在则创建
        if not os.path.exists(dst_dir):
            os.makedirs(dst_dir)

        # 遍历源目录中的所有文件
        for filename in os.listdir(src_dir):
            file_path = os.path.join(src_dir, filename)

            # 检查是否为文件
            if os.path.isfile(file_path) and self.is_image_file(filename):
                # 构造目标文件的路径
                dst_file_path = os.path.join(dst_dir, filename)

                # 复制文件
                shutil.copy2(file_path, dst_file_path)
                print(f"Copied {file_path} to {dst_file_path}")
                # 忽略子目录

    def check_file(self, src_path):
        file_path = src_path
        # 在这里处理选中的文件，例如加载或显示它
        file_extension, flag = self.is_image_or_icns_file(file_path)
        if flag:
            if file_extension == ".iconset":
                # 选择清晰度最高的展示
                highest_image_path = self.find_highest_image(file_path)
                if highest_image_path:
                    self.view.loadPixmapFromFile(highest_image_path)
                    self.clear_temp_iconset()
                    # 复制.iconset的文件到临时文件夹
                    self.cp_imgs_to_dir(file_path, self.temp_iconset)
                    file_path = self.temp_iconset
                else:
                    self.show_message_box("未发现图片")
                    return
            elif file_extension == ".app":
                file_name = self.find_icns_from_app(file_path)
                if not file_name:
                    self.show_message_box("未找到.icns文件")
                    return
                file_path = f'{file_path}/{file_name}'
                self.view.loadPixmapFromFile(file_path)
            else:
                # 显示图片
                self.view.loadPixmapFromFile(file_path)

            self.handle_img(file_path, file_extension, src_path)
        else:
            self.show_message_box("请选择图片｜.icns .app|.iconset")

    def find_icns_from_app(self, app_path):
        app_path = f'{app_path}/Contents/Resources'
        if os.path.exists(app_path) and os.path.isdir(app_path):
            files = os.listdir(app_path)
            if files:
                files.sort()
                for filename in files:
                    if filename.endswith(".icns"):
                        return f'Contents/Resources/{filename}'

    def on_remove_clicked(self):
        if self.current_table_row >= 0:
            item = self.model.item(self.current_table_row, 2)
            if not item:
                return
            # 判断缓存的文件是否存在
            if self.current_mode == C_MODE.MODE_3:
                src_path = item.data()
                if src_path and os.path.exists(src_path):
                    os.remove(src_path)
            file_path = item.text()
            self.model.removeRow(self.current_table_row)
            os.remove(file_path)
            self.current_table_row = -1

            if self.model.rowCount() == 0:
                self.view.loadPixmapFromFile(f"{self.base_path}/resource/info.png")
                self.reset_window(False, C_MODE.MODE_0)

    def show_message_box(self, info):
        # 创建一个QMessageBox实例
        msgBox = QMessageBox(self)

        # 设置提示框的标题和文本
        msgBox.setWindowTitle("提示")
        msgBox.setText(info)

        # 设置提示框的图标（可选，可以是QMessageBox.Information, QMessageBox.Warning, QMessageBox.Critical等）
        msgBox.setIcon(QMessageBox.Information)

        # 显示提示框，并等待用户响应
        msgBox.exec()

    def on_table_clicked(self, index: QModelIndex):
        # 检查 index 是否有效
        if index.isValid():
            # 获取被点击的行的索引
            row = index.row()
            column = index.column()
            col = 2
            index2 = self.model.index(row, col)
            file_path = self.model.data(index2)
            print(f"Data at row {row}, column {column}: {file_path}")
            self.view.loadPixmapFromFile(file_path)

            index0 = self.model.index(row, 0)
            file_name = self.model.data(index0)
            file_name_item = self.model.itemFromIndex(index0)
            item_0_data = file_name_item.data()
            if not item_0_data:
                trans_val = self.get_trans_by_file_name(file_name)  # 取默认值
                file_name_item.setData(str(trans_val))
            else:
                trans_val = int(item_0_data)
            self.trans_slider.set_value(trans_val)

            self.current_table_row = row
            if column == col:
                self.open_file_location(file_path)

    def get_trans_by_file_name(self, file_name):
        for key, val in self.ratios.items():
            if key in file_name:
                return self.slides_vals[val]

        return 3

    def open_file_location(self, file_path):
        # 获取文件所在的目录
        directory = os.path.dirname(file_path)

        # 使用操作系统的默认文件管理器打开该目录
        if os.name == 'nt':  # Windows
            os.startfile(directory)
        elif os.name == 'posix':  # macOS/Linux
            if os.path.exists(directory) and os.path.isdir(directory):
                if str.endswith(directory, '.iconset'):
                    directory = os.path.dirname(directory)
                try:
                    subprocess.run(["open", directory])
                except Exception as e:
                    self.show_message_box("打开png文件所在文件夹失败！")

    def is_image_or_icns_file(self, filename):
        if filename and (filename.endswith(".iconset/") or filename.endswith(".app/")):
            filename = filename[:-1]
        # 定义一组已知的图片文件扩展名
        file_extensions = self.image_extensions
        # 添加.icns扩展名
        file_extensions.add('.icns')
        file_extensions.add('.app')
        file_extensions.add('.iconset')

        # 提取文件的扩展名
        _, file_extension = os.path.splitext(filename)

        # 检查文件的扩展名是否在已知的图片或.icns扩展名列表中
        return file_extension.lower(), file_extension.lower() in file_extensions

    def keyPressEvent(self, event):
        if (event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_V):
            # 处理粘贴命令
            clipboard = QApplication.clipboard()
            mime_data = clipboard.mimeData()
            if mime_data.hasImage():

                try:
                    # 从剪切板获取图片数据
                    image = mime_data.imageData()
                    # 将 QImage 转换为 QPixmap 以展示
                    pixmap = QPixmap.fromImage(image)
                    # 设置 QLabel 的 pixmap 属性以显示图片
                    self.view.loadPixmapFromPixmap(pixmap)

                    # 使用 QImageWriter 将图片保存到文件
                    image_writer = QImageWriter()
                    image_writer.setFileName(self.temp_clip_path)

                    # 写入图片到文件
                    success = image_writer.write(image)

                    if success:
                        self.handle_img(self.temp_clip_path, ".png")
                except Exception as e:
                    self.show_message_box("从剪切板获取图片数据失败！{e}")
                    return
            else:
                print("No image in clipboard.")
        else:
            super().keyPressEvent(event)  # 调用基类处理其他按键事件

    def crop_and_square_png(self, img_path, ratio):
        # 创建一个掩码来找到非透明区域的边界框
        img = PILImage.open(img_path)
        bbox = img.getbbox()

        # 根据非透明区域裁剪图片
        cropped_img = img.crop(bbox)

        # 计算需要填充的边长，以使图片变为正方形
        side_length = int(max(cropped_img.size) * ratio)

        # 创建一个新的正方形画布，并用指定颜色填充
        new_img = PILImage.new('RGBA', (side_length, side_length))

        # 计算粘贴的位置，以保持裁剪内容居中
        paste_position = ((side_length - cropped_img.width) // 2, (side_length - cropped_img.height) // 2)

        # 将裁剪后的图片粘贴到正方形画布上
        new_img.paste(cropped_img, paste_position)
        temp_png_path = f'{self.cache_path}/{uuid.uuid4()}.png'
        new_img.save(temp_png_path)
        return temp_png_path

    def handle_img(self, file_path, file_extension, src_path=None):
        if file_extension == ".icns" or file_extension == ".app":
            self.extract_icns_info(file_path)
            # 填充模型
            self.populate_model(self.temp_iconset)
            self.reset_window(True, C_MODE.MODE_3)
        elif file_extension == ".iconset":
            # 填充模型
            self.populate_model(file_path, src_path)
            self.reset_window(True, C_MODE.MODE_2)
        else:
            self.save_to_pngs(file_path, self.temp_iconset)
            # 填充模型
            self.populate_model(self.temp_iconset)
            self.reset_window(True, C_MODE.MODE_1)

    def reset_window(self, save_button_enabled, current_mode):
        self.current_mode = current_mode
        self.save_button.setEnabled(save_button_enabled)
        self.remove_button.setEnabled(save_button_enabled)
        self.trans_slider.setEnabled(save_button_enabled)

    def save_to_pngs(self, file_path, output_dir):
        self.temp_clip_path = file_path
        # 清理一下缓存文件
        self.clear_temp_dir()
        img = PILImage.open(file_path)
        dialog = MultiCheckDialog(self, max(img.size))
        result = dialog.exec()
        if result == QDialog.Accepted:
            print("对话框被接受")
        else:
            print("对话框被取消")
            return
        try:
            t1 = time.time()
            threads = []
            # 遍历字典的键值对
            for option, is_checked in self.selected_options.items():
                print(f"选项: {option}, 是否被选中: {is_checked}")
                if is_checked:
                    thread = threading.Thread(target=self.running_task, args=(option, file_path, output_dir))
                    threads.append(thread)
                    thread.start()
            # 等待所有线程完成
            for thread in threads:
                thread.join()
            t2 = time.time()
            print(f'耗时：{t2 - t1}')

        except Exception as e:
            self.show_message_box("生成ico文件失败！")

    def running_task(self, option, file_path, output_dir):
        try:
            ico_size = self.get_ico_size(option)
            png_path = self.crop_and_square_png(file_path, self.ratios[option])
            print(png_path)
            subprocess.run(["sips", "-z", str(ico_size), str(ico_size), png_path, "--out",
                            f'{output_dir}/icon_{option}.png'], check=True)
            os.remove(png_path)
        except Exception as e:
            print("生成png文件失败！")

    def clear_temp_iconset(self):
        if os.listdir(self.temp_iconset):
            # 如果目录不为空，则删除它及其内容
            shutil.rmtree(self.temp_iconset)
        os.makedirs(self.temp_iconset, exist_ok=True)

    def extract_icns_info(self, icns_path):
        try:
            self.clear_temp_iconset()
            # 使用iconutil命令提取icns到临时目录
            subprocess.run(["iconutil", "-c", "iconset", icns_path, "-o", self.temp_iconset], check=True)
        except Exception as e:
            self.show_message_box(f"解析icns文件失败！{e}")
            return
        # 遍历提取出的PNG文件，获取尺寸
        sizes = []
        for png_file in glob.glob(os.path.join(self.temp_iconset, "*.png")):
            with PILImage.open(png_file) as img:
                sizes.append((img.width, img.height))

        return sizes
    def clear_model(self):
        # 判断缓存的文件是否存在
        if self.current_mode == C_MODE.MODE_3:
            for row in range(self.model.rowCount()):
                item = self.model.item(row, 2)
                src_path = item.data()
                if src_path and os.path.exists(src_path):
                    os.remove(src_path)
        self.model.clear()
    def populate_model(self, directory, src_path=None):
        # 清空模型数据
        self.clear_model()
        files = os.listdir(directory)
        # 创建一个字典来存储文件名和它们的大小
        file_filenames = {}
        self.model.setHorizontalHeaderLabels(['名称（可点击）', '大小', '地址（可点击查看）', '尺寸'])
        for filename in files:
            filepath = os.path.join(directory, filename)
            if os.path.isfile(filepath):  # 确保是文件而不是目录
                strs = str.split(filename, 'x')
                match = re.search(r'icon_(\d+)x', filename)
                if match:
                    size = match.group(1)  # 提取"64"
                    print(size)
                    if int(size) < 100:
                        f_name = f'0{size}{strs[1]}'
                    else:
                        f_name = f'{size}{strs[1]}'
                else:
                    f_name = filename
                file_filenames[filename] = f_name

        sorted_files = sorted(file_filenames.items(), key=lambda x: x[1], reverse=False)  # reverse=False 表示正序排序

        for filename, size in sorted_files:
            filepath = os.path.join(directory, filename)
            file_info = QFileInfo(filepath)
            # 加载图像
            image = QImage(filepath)

            # 检查图像是否有效加载
            if image.isNull():
                return None

            # 返回图像的宽度和高度
            image_size = f'{image.width()}x{image.height()}'
            # 创建项目并添加到模型
            name_item = QStandardItem(file_info.fileName())
            size_item = QStandardItem(f'{int(file_info.size() / 1000)}KB')
            path_item = QStandardItem(filepath)
            image_size_item = QStandardItem(image_size)
            # 将原文件路径缓存在path_item的data里
            if src_path:
                path_item.setData(os.path.join(src_path,file_info.fileName())) # reset_png方法微调时会用到

            self.model.appendRow([name_item, size_item, path_item, image_size_item])
        # 设置水平表头的拉伸策略，这里假设我们想要第二列（索引为1）占据剩余空间
        header = self.tableView.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.ResizeToContents)  # 第一列根据内容调整大小
        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QHeaderView.ResizeToContents)  # 拉伸以占据剩余空间
        header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
    def save_icns(self):
        # 设置文件对话框的标题
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getSaveFileName(self, "选择保存位置", "", "All Files (*.icns);;PNG Files (*.icns)",
                                                  options=options)

        # 检查用户是否确实选择了一个文件（没有点击取消）
        if fileName:
            print(f"用户选择了保存路径: {fileName}")
            if not str.endswith(fileName, '.icns'):
                fileName = f'{fileName}.icns'
            # 在这里可以进行文件保存的操作
            try:
                subprocess.run(["iconutil", "-c", "icns", self.temp_iconset], check=True)
                icns_path = os.path.splitext(self.temp_iconset)[0]
                shutil.move(f'{icns_path}.icns', fileName)
                self.show_message_box("保存成功！")
            except Exception as e:
                self.show_message_box("保存失败！")

    def get_ico_size(self, option):
        # option
        res = str.split(option, 'x')
        if "@" in option:
            return 2 * int(res[0])
        else:
            return int(res[0])

    def mk_cache_dir(self, file_name):
        # 获取当前用户的家目录
        home_dir = os.path.expanduser("~")
        # 检查文件是否存在
        cache_path = f"{home_dir}/{file_name}"
        os.makedirs(cache_path, exist_ok=True)
        return cache_path

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWin()
    window.setWindowTitle('icns生成器')
    window.show()
    sys.exit(app.exec())
